<?php
/**
 * ***********************************************************************************
 * 知识商城PC端，独立域名自动部署Apache
 * 
 * @author Mr.RJH
 * @date 2025-11-26
 * @email<15213026209@163.com>
 * ***********************************************************************************
 */
namespace app\service;

use think\facade\Log;
use think\facade\Config;

class ApacheConfigService
{
    // 使用项目runtime目录
    protected $localConfigDir;
    protected $sslBaseDir;
    protected $logBaseDir;
    
    public function __construct()
    {
        $this->localConfigDir = app()->getRuntimePath() . 'apache_configs/'; // apache配置目录
        $this->sslBaseDir = app()->getRuntimePath() . 'apache_ssls/'; // 证书目录
        $this->logBaseDir = app()->getRuntimePath() . 'apache_logs/'; // 日志目录
        // 确保目录存在
        $this->createDirectories();
    }
    
    /**
     * 创建必要的目录
     */
    private function createDirectories()
    {
        $dirs = [
            $this->localConfigDir,
            $this->sslBaseDir . 'certs/',
            $this->sslBaseDir . 'private/',
            $this->logBaseDir,
        ];
        
        foreach ($dirs as $dir) {
            if (!is_dir($dir) && !mkdir($dir, 0755, true)) {
                throw new \Exception("无法创建目录: {$dir}");
            }
        }
    }
    
    /**
     * 生成Apache虚拟主机配置
     * 
     * @param $domainRecord 域名申请记录
     * @param $targetDomain 代理目标域名
     */
    public function generateVhostConfig($domainRecord, $targetDomain)
    {
        $domain = $domainRecord['domain'];

        $certFile = $this->sslBaseDir . 'certs/' . $domain . '.crt';
        $keyFile = $this->sslBaseDir . 'private/' . $domain . '.key';

        $errorLog = $this->logBaseDir . $domain . '-error.log';
        $accessLog = $this->logBaseDir . $domain . '-access.log';

        if ($domainRecord['pem_url'] && $domainRecord['key_url']) {
            $config = <<<EOT
            <VirtualHost *:80>
                ServerName {$domain}
                ServerAlias {$domain}
                
                # 可选HTTP重定向到HTTPS
                # RewriteEngine On
                # RewriteCond %{HTTPS} off
                # RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
                
                # 使用mod_rewrite进行代理
                RewriteEngine On
                RewriteRule ^(.*)$ http://{$targetDomain}$1 [P,L]
                
                # 处理响应头
                ProxyPassReverse / http://{$targetDomain}/
                
                # 日志文件
                ErrorLog {$errorLog}
                CustomLog {$accessLog} combined
            </VirtualHost>
            
            <VirtualHost *:443>
                ServerName {$domain}
                ServerAlias {$domain}
                
                # SSL配置
                SSLEngine on
                SSLCertificateFile {$certFile}
                SSLCertificateKeyFile {$keyFile}
                
                # 安全头设置
                Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
                Header always set X-Content-Type-Options nosniff
                
                # 使用mod_rewrite进行代理（与80端口保持一致）
                RewriteEngine On
                RewriteRule ^(.*)$ http://{$targetDomain}$1 [P,L]
            
                # 处理响应头
                ProxyPassReverse / http://{$targetDomain}/
                
                # 日志文件
                ErrorLog {$errorLog}
                CustomLog {$accessLog} combined
                
                # 超时设置
                ProxyTimeout 300
            </VirtualHost>
            EOT;
        } else {
            $config = <<<EOT
            <VirtualHost *:80>
                ServerName {$domain}
                ServerAlias {$domain}
                
                # 可选HTTP重定向到HTTPS
                # RewriteEngine On
                # RewriteCond %{HTTPS} off
                # RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
                
                # 使用mod_rewrite进行代理
                RewriteEngine On
                RewriteRule ^(.*)$ http://{$targetDomain}$1 [P,L]
                
                # 处理响应头
                ProxyPassReverse / http://{$targetDomain}/
                
                # 日志文件
                ErrorLog {$errorLog}
                CustomLog {$accessLog} combined
            </VirtualHost>
            EOT;
        }

        return $config;
    }


    /**
     * 保存SSL证书文件
     */
    public function saveSSLCertificates($domain, $certContent, $keyContent)
    {
        try {
            $certDir = $this->sslBaseDir . 'certs/';
            $keyDir = $this->sslBaseDir . 'private/';
            
            // 保存证书文件
            $certFile = $certDir . $domain . '.crt';
            if (file_put_contents($certFile, $certContent) === false) {
                throw new \Exception("写入证书文件失败: {$certFile}");
            }
            chmod($certFile, 0644);
            
            // 保存私钥文件
            $keyFile = $keyDir . $domain . '.key';
            if (file_put_contents($keyFile, $keyContent) === false) {
                if (file_exists($certFile)) unlink($certFile);
                throw new \Exception("写入私钥文件失败: {$keyFile}");
            }
            chmod($keyFile, 0600);
            
            Log::info("SSL证书保存成功: {$certFile}, {$keyFile}");
            return [
                'cert_file' => $certFile,
                'key_file' => $keyFile
            ];
            
        } catch (\Exception $e) {
            Log::error('保存SSL证书失败: ' . $e->getMessage());
            return false;
        }
    }
    
    /**
     * 部署Apache配置
     */
    public function deployConfig($domain, $configContent)
    {
        try {
            Log::info("开始部署Apache配置: {$domain}");
            
            // 1. 保存配置文件到本地目录
            $localConfigFile = $this->localConfigDir . $domain . '.conf';
            if (file_put_contents($localConfigFile, $configContent) === false) {
                throw new \Exception("写入配置文件失败: {$localConfigFile}");
            }
            Log::info("配置文件保存成功: {$localConfigFile}");
            
            // 2. 生成详细的部署指南
            $guide = $this->generateDeploymentGuide($domain);
            // 3. 记录成功状态
            Log::info("Apache配置已保存，请按照指南手动完成部署: {$domain}");
            
            return [
                'success' => true,
                'config_file' => $localConfigFile,
                'message' => '配置已保存，需要手动完成Apache部署',
                'guide_file' => $this->localConfigDir . 'DEPLOYMENT_GUIDE.md',
                'guide' => $guide,
            ];
            
        } catch (\Exception $e) {
            Log::error('部署Apache配置失败: ' . $e->getMessage());
            return [
                'success' => false,
                'error' => $e->getMessage()
            ];
        }
    }

    /**
     * 生成详细的部署指南（Markdown格式）
     */
    private function generateDeploymentGuide($domain)
    {
        $guideFile = $this->localConfigDir . 'DEPLOYMENT_GUIDE.md';
        
        $localConfigFile = $this->localConfigDir . $domain . '.conf';
        $certFile = $this->sslBaseDir . 'certs/' . $domain . '.crt';
        $keyFile = $this->sslBaseDir . 'private/' . $domain . '.key';
        
        $guide = "## 部署域名: {$domain}" . PHP_EOL . PHP_EOL;
        
        $guide .= "📁 文件位置" . PHP_EOL;
        $guide .= "- **配置文件**: `{$localConfigFile}`" . PHP_EOL;
        $guide .= "- **SSL证书**: `{$certFile}`" . PHP_EOL;
        $guide .= "- **SSL私钥**: `{$keyFile}`" . PHP_EOL . PHP_EOL;
        
        $guide .= "🚀 部署步骤 (CentOS)" . PHP_EOL;

        // 首次部署需要创建目录等
        // $guide .= "# 1、创建目录（按Enter执行）" . PHP_EOL;
        // $guide .= "sudo mkdir -p /etc/httpd/conf.d/" . PHP_EOL;
        // $guide .= "# 2、创建目录（按Enter执行）" . PHP_EOL;
        // $guide .= "echo 'Include {$this->localConfigDir}*.conf' | sudo tee /etc/httpd/conf.d/local-sites.conf" . PHP_EOL;
        // $guide .= "# 3、测试配置" . PHP_EOL;
        // $guide .= "sudo httpd -t" . PHP_EOL;
        // $guide .= "# 4、重新加载Apache" . PHP_EOL;
        // $guide .= "sudo httpd -k graceful" . PHP_EOL;
        // 后续商户申请独立域名只需重启Apache生效即可
        $guide .= "# 前往服务器面板终端执行下面命令" . PHP_EOL;
        $guide .= "# 1、创建符号链接到Apache配置目录" . PHP_EOL;
        $guide .= "ln -sf /wwwroot/webpc.zixunli.cn/runtime/apache_configs/{$domain}.conf /www/server/panel/vhost/apache/{$domain}.conf" . PHP_EOL;
        $guide .= "# 2、重启Apache生效" . PHP_EOL;
        $guide .= "sudo httpd -k graceful" . PHP_EOL;
        
        # 1. 移除当前符号链接配置
        // rm -f /www/server/panel/vhost/apache/sizih.tikaola.com.conf
        // file_put_contents($guideFile, $guide);
        // Log::info("部署指南已生成: {$guideFile}");
        return $guide;
    }

    /**
     * 验证部署状态
     */
    public function verifyDeployment($domain)
    {
        $result = [
            'domain' => $domain,
            'config_file' => $this->localConfigDir . $domain . '.conf',
            'config_exists' => file_exists($this->localConfigDir . $domain . '.conf'),
            'cert_file' => $this->sslBaseDir . 'certs/' . $domain . '.crt',
            'cert_exists' => file_exists($this->sslBaseDir . 'certs/' . $domain . '.crt'),
            'key_file' => $this->sslBaseDir . 'private/' . $domain . '.key',
            'key_exists' => file_exists($this->sslBaseDir . 'private/' . $domain . '.key'),
            'status' => 'config_saved',
            'message' => '配置已保存到项目目录，等待手动部署到Apache'
        ];
        
        return $result;
    }
    
    /**
     * 获取部署摘要
     */
    public function getDeploymentSummary($domain)
    {
        $status = $this->verifyDeployment($domain);
        
        $summary = "## 域名部署状态: {$domain}" . PHP_EOL . PHP_EOL;
        $summary .= "✅ **配置文件**: 已保存 (`{$status['config_file']}`)" . PHP_EOL;
        $summary .= "✅ **SSL证书**: 已保存 (`{$status['cert_file']}`)" . PHP_EOL;
        $summary .= "✅ **私钥文件**: 已保存 (`{$status['key_file']}`)" . PHP_EOL . PHP_EOL;
        $summary .= "⚠️ **Apache状态**: 需要手动部署" . PHP_EOL . PHP_EOL;
        $summary .= "## 下一步操作" . PHP_EOL . PHP_EOL;
        $summary .= "请系统管理员按照以下指南完成部署：" . PHP_EOL;
        $summary .= "`{$this->localConfigDir}DEPLOYMENT_GUIDE.md`" . PHP_EOL . PHP_EOL;
        $summary .= "**预计耗时**: 5-10分钟";
        
        return $summary;
    }
}